package org.convallaria.system.biz.aspect;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.convallaria.system.biz.service.PerformanceMonitorService;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 性能监控切面
 * 提供安全的性能监控功能，避免循环调用问题
 * 
 * @author convallaria
 * @since 1.0.0
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class PerformanceMonitorAspect {

    private final PerformanceMonitorService performanceMonitorService;
    
    // 使用ThreadLocal避免循环调用
    private final ThreadLocal<AtomicBoolean> monitoringFlag = ThreadLocal.withInitial(() -> new AtomicBoolean(false));
    
    // 缓存已监控的方法，避免重复监控
    private final ConcurrentHashMap<String, Boolean> monitoredMethods = new ConcurrentHashMap<>();

    /**
     * 监控Controller层性能
     */
    @Around("execution(* org.convallaria.system.biz.controller.*.*(..))")
    public Object monitorController(ProceedingJoinPoint joinPoint) throws Throwable {
        return monitorMethod(joinPoint, "Controller");
    }

    /**
     * 监控Service层性能（排除监控相关服务）
     */
    @Around("execution(* org.convallaria.system.biz.service.impl.*.*(..)) && " +
            "!execution(* org.convallaria.system.biz.service.impl.PerformanceMonitorServiceImpl.*(..)) && " +
            "!execution(* org.convallaria.system.biz.service.impl.CacheOptimizationServiceImpl.*(..)) && " +
            "!execution(* org.convallaria.system.biz.service.impl.SecurityConfigServiceImpl.*(..))")
    public Object monitorService(ProceedingJoinPoint joinPoint) throws Throwable {
        return monitorMethod(joinPoint, "Service");
    }

    /**
     * 监控Mapper层性能
     */
    @Around("execution(* org.convallaria.system.biz.mapper.*.*(..))")
    public Object monitorMapper(ProceedingJoinPoint joinPoint) throws Throwable {
        return monitorMethod(joinPoint, "Mapper");
    }

    /**
     * 通用方法监控
     */
    private Object monitorMethod(ProceedingJoinPoint joinPoint, String layer) throws Throwable {
        String methodName = getMethodName(joinPoint);
        
        // 检查是否已经在监控中，避免循环调用
        if (monitoringFlag.get().get()) {
            return joinPoint.proceed();
        }
        
        // 检查是否已经监控过此方法
        if (monitoredMethods.containsKey(methodName)) {
            return joinPoint.proceed();
        }
        
        // 设置监控标志
        monitoringFlag.get().set(true);
        monitoredMethods.put(methodName, true);
        
        long startTime = System.currentTimeMillis();
        boolean success = true;
        Object result = null;

        try {
            result = joinPoint.proceed();
            return result;
        } catch (Exception e) {
            success = false;
            throw e;
        } finally {
            long duration = System.currentTimeMillis() - startTime;
            
            try {
                // 异步记录性能数据，避免阻塞主流程
                recordPerformanceAsync(methodName, duration, success, layer);
                
                if (duration > 1000) { // 超过1秒记录警告
                    log.warn("慢操作检测: {} - {} 执行时间: {}ms", layer, methodName, duration);
                }
            } catch (Exception e) {
                log.error("记录性能监控数据失败", e);
            } finally {
                // 重置监控标志
                monitoringFlag.get().set(false);
            }
        }
    }

    /**
     * 异步记录性能数据
     */
    private void recordPerformanceAsync(String methodName, long duration, boolean success, String layer) {
        try {
            // 使用简单的异步方式记录，避免复杂的异步处理
            performanceMonitorService.recordApiPerformance(methodName, duration, success);
        } catch (Exception e) {
            log.debug("异步记录性能数据失败: {}", e.getMessage());
        }
    }

    /**
     * 获取方法名
     */
    private String getMethodName(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = method.getDeclaringClass().getSimpleName();
        String methodName = method.getName();
        return className + "." + methodName;
    }
}
